package com.such.kit.io.bean;

import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.Workbook;
import com.alibaba.fastjson.annotation.JSONField;
import com.such.kit.io.simple.support.IOSimple;
import com.such.kit.io.source.DatabaseIOSource;
import com.such.kit.io.template.ExcelIOTemplate;
import com.such.kit.io.template.support.IOTemplate;
import com.such.kit.placeholder.PlaceholderCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * ExcelIOConfig 需要兼容的场景相对复杂，不但有 [导入时] [导出时] 还有 [简单模式时] [使用模板时]，看使用变量时可以关注其标签
 * 这里对 [简单模式时] [使用模板时] 相关的变量做重点说明
 *   [简单模式时]
 *     需要设置 {@link #titleTemplate}、{@link #dataTemplate}
 *     由于此模式没有工作表模板，只能根据表头、数据模板自动生成默认工作表模板，同时可以对 {@link #maxRow}、{@link #dataArea}、{@link #maxCol} 进行赋值
 *     最后基于生成的工作表模板创建工作簿赋值给 {@link #templateWorkbook}
 *   [使用模板时]
 *     需要在模板中 {@link ExcelIOTemplate 配置} {@link #maxRow}、{@link #dataArea}、{@link #maxCol}
 *     系统在 {@link IOTemplate#initTemplate} 时会获取 ExcelIOConfig 对应的工作表模板
 *     基于工作表模板创建工作簿赋值给 {@link #templateWorkbook}
 * 
 * {@link #templateWorkbook} 虽然提供了 set 方法，但是不建议在外部对其进行赋值，让系统自动生成便可
 * </pre>
 */
public class ExcelIOConfig {

	/** IO_C：Excel 中 Sheet 配置页、配置单元的指定名称 */
	public static final String IO_C = "IO_C";
	public static final String IO_SHEET_NAME = "IO_SHEET_NAME";
	public static final String IO_MAX_ROW = "IO_MAX_ROW";
	public static final String IO_MAX_COL = "IO_MAX_COL";
	public static final String IO_DATA_AREA = "IO_DATA_AREA";
	public static final String IO_SHEET_SIZE = "IO_SHEET_SIZE";
	public static final String IO_INPUT_EXPRESSION = "IO_INPUT_EXPRESSION";
	public static final String IO_OUTPUT_EXPRESSION = "IO_OUTPUT_EXPRESSION";

	/**
	 * defaultConfig：[导入时] 是否作为默认 ExcelIOConfig [默认值为 false]
	 * <pre>
	 * 当未找到导入的 sheet 名称对应的 ExcelIOConfig 时，取 defaultConfig 为 ExcelIOConfig
	 * [简单模式时] 的导入介质缺乏约束性，无法保证其 sheet 名称符合 {@link #sheetName} 规则，因此添加此选项增强容错性
	 * 
	 * [警告] 系统最多只能接收 1 个 defaultConfig，如果多个 ExcelIOConfig 的 defaultConfig 为 true，会一直覆盖而接收最后 1 个
	 * </pre>
	 */
	private boolean defaultConfig;
	/**
	 * sheetName：模板工作表名称
	 * <pre>
	 * [导入时] 系统根据 sheetName 匹配 ExcelIOConfig
	 * [导出时] 系统根据 sheetName 规则生成工作表名称
	 * </pre>
	 */
	@JSONField(name = IO_SHEET_NAME)
	private String sheetName;
	/**
	 * maxRow：[使用模板时] 模板最大行 [下标 1] [默认值为 0]
	 * <pre>
	 * [警告] 在计算最大行时不应排除空白行，如表头从第 2 行开始，第 1 行的空白行也应该计算在内
	 * </pre>
	 */
	@JSONField(name = IO_MAX_ROW)
	private int maxRow;
	/** dataArea：[使用模板时] 模板中数据所在行 [下标 1] [默认值为 0] */
	@JSONField(name = IO_DATA_AREA)
	private int dataArea;
	/**
	 * maxCol：[使用模板时] 模板最大列 [下标 1] [默认值为 0]
	 * <pre>
	 * [警告] 在计算最大列时不应排除空白列，如从第 2 列开始有实际数据，第 1 列的空白列也应该计算在内
	 * </pre>
	 */
	@JSONField(name = IO_MAX_COL)
	private int maxCol;
	/**
	 * titleTemplate：[简单模式时] [导出时] 表头模板
	 * <pre>
	 * [警告] titleTemplate 与 dataTemplate 必须一一对应，否则会导致表头与数据错行，系统会避免错行产生而输出空表头
	 * [举例] ["用户名", "表名", "表说明"]
	 * </pre>
	 */
	private List<String> titleTemplate;
	/**
	 * dataTemplate：[简单模式时] [导出时] 数据行模板，可以使用 {@link PlaceholderCommons 占位符} 引用 IO 数据、{@link IOSimple#args 自定义参数}
	 * <pre>
	 * 系统可以根据 rowTemplate、dataTemplate 自动计算出 maxRow、dataArea、maxCol
	 *   maxRow = (titleTemplate is null ? 1 : 2)
	 *   dataArea = (titleTemplate is null ? 1 : 2)
	 *   maxCol = rowTemplate.size
	 * 
	 * [警告] dataTemplate 中元素顺序即为导出顺序，如从第 2 列开始有实际数据，第 1 列的空白列在 dataTemplate 中不应忽略，应该计为 null
	 * [举例] ["#[schema]", "#[tableName]", "#[tableComment]"]
	 * </pre>
	 */
	private List<String> dataTemplate;
	/**
	 * templateWorkbook：工作簿模板
	 * <pre>
	 * 由系统自动生成，提供一个通用的导入、导出工作簿模板
	 * </pre>
	 */
	private Workbook templateWorkbook;
	/**
	 * sheetSize：[导出时] 每个工作表的最大行数 [默认值为 50000]
	 * <pre>
	 * 超过 50000 系统则创建一个新的工作表
	 * </pre>
	 */
	@JSONField(name = IO_SHEET_SIZE)
	private int sheetSize = 50000;
	/**
	 * inputExpression：[导入时] 表达式
	 * <pre>
	 * {@link IOSource} 的不同实现 inputExpression 的推荐值有所变化
	 * 以 {@link DatabaseIOSource} 为例，inputExpression 的推荐值为 sql 语句
	 * [举例] ["insert into TABLE_INFO (schema, name, comment) value (:schema, :tableName, :tableComment)"]
	 * </pre>
	 */
	@JSONField(name = IO_INPUT_EXPRESSION)
	private List<String> inputExpression;
	/**
	 * outputExpression：[导出时] 表达式
	 * <pre>
	 * {@link IOSource} 的不同实现 outputExpression 的推荐值有所变化
	 * 以 {@link DatabaseIOSource} 为例，outputExpression 的推荐值为 sql 语句
	 * [举例] "select schema as schema, name as tableName, comment as tableComment from TABLE_INFO"
	 * </pre>
	 */
	@JSONField(name = IO_OUTPUT_EXPRESSION)
	private String outputExpression;

	/** [参考 {@link #defaultConfig}] */
	public boolean isDefaultConfig() {
		return this.defaultConfig;
	}

	/** [参考 {@link #defaultConfig}] */
	public void setDefaultConfig(boolean defaultConfig) {
		this.defaultConfig = defaultConfig;
	}

	/** [参考 {@link #sheetName}] */
	public String getSheetName() {
		return this.sheetName;
	}

	/** [参考 {@link #sheetName}] */
	public void setSheetName(String sheetName) {
		this.sheetName = sheetName;
	}

	/** [参考 {@link #maxRow}] */
	public int getMaxRow() {
		return this.maxRow;
	}

	/** [参考 {@link #maxRow}] */
	public void setMaxRow(int maxRow) {
		this.maxRow = maxRow;
	}

	/** [参考 {@link #dataArea}] */
	public int getDataArea() {
		return this.dataArea;
	}

	/** [参考 {@link #dataArea}] */
	public void setDataArea(int dataArea) {
		this.dataArea = dataArea;
	}

	/** [参考 {@link #maxCol}] */
	public int getMaxCol() {
		return this.maxCol;
	}

	/** [参考 {@link #maxCol}] */
	public void setMaxCol(int maxCol) {
		this.maxCol = maxCol;
	}

	/** [参考 {@link #titleTemplate}] */
	public List<String> getTitleTemplate() {
		return this.titleTemplate;
	}

	/** [参考 {@link #titleTemplate}] */
	public void setTitleTemplate(List<String> titleTemplate) {
		this.titleTemplate = titleTemplate;
	}

	/** [参考 {@link #titleTemplate}] */
	public void addTitleTemplate(String titleTemplate) {
		if (ValidateCommons.isEmpty(this.titleTemplate)) {
			this.titleTemplate = new ArrayList<String>();
		}
		this.titleTemplate.add(titleTemplate);
	}

	/** [参考 {@link #dataTemplate}] */
	public List<String> getRowTemplate() {
		return this.dataTemplate;
	}

	/** [参考 {@link #dataTemplate}] */
	public void setRowTemplate(List<String> rowTemplate) {
		this.dataTemplate = rowTemplate;
	}

	/** [参考 {@link #dataTemplate}] */
	public void addRowTemplate(String rowTemplate) {
		if (ValidateCommons.isEmpty(this.dataTemplate)) {
			this.dataTemplate = new ArrayList<String>();
		}
		this.dataTemplate.add(rowTemplate);
	}

	/** [参考 {@link #titleTemplate} {@link #dataTemplate}] */
	public void addColTemplate(String titleTemplate, String rowTemplate) {
		addTitleTemplate(titleTemplate);
		addRowTemplate(rowTemplate);
	}

	/** [参考 {@link #templateWorkbook}] */
	public Workbook getTemplateWorkbook() {
		return this.templateWorkbook;
	}

	/** [参考 {@link #templateWorkbook}] */
	public void setTemplateWorkbook(Workbook templateWorkbook) {
		this.templateWorkbook = templateWorkbook;
	}

	/** [参考 {@link #sheetSize}] */
	public int getSheetSize() {
		return this.sheetSize;
	}

	/** [参考 {@link #sheetSize}] */
	public void setSheetSize(int sheetSize) {
		this.sheetSize = sheetSize;
	}

	/** [参考 {@link #inputExpression}] */
	public List<String> getInputExpression() {
		return this.inputExpression;
	}

	/** [参考 {@link #inputExpression}] */
	public void setInputExpression(List<String> inputExpression) {
		this.inputExpression = inputExpression;
	}

	/** [参考 {@link #inputExpression}] */
	public void addInputExpression(String ie) {
		if (ValidateCommons.isEmpty(this.inputExpression)) {
			this.inputExpression = new ArrayList<String>();
		}
		this.inputExpression.add(ie);
	}

	/** [参考 {@link #outputExpression}] */
	public String getOutputExpression() {
		return this.outputExpression;
	}

	/** [参考 {@link #outputExpression}] */
	public void setOutputExpression(String outputExpression) {
		this.outputExpression = outputExpression;
	}

}
